﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Threading;

namespace SocketClient
{
    /// <summary>
    /// 
    /// </summary>
    public class SerialPortManager
    {

        #region ReceivedDelayHelper
        private class ReceivedDelayHelper
        {
            /// <summary>
            /// 
            /// </summary>
            private Thread _receiveDelayThread = null;

            /// <summary>
            /// 
            /// </summary>
            private DateTime _receiveDelayStartDateTime;

            /// <summary>
            /// 
            /// </summary>
            private SerialPortManager _serialPortManager;

            /// <summary>
            /// 
            /// </summary>
            /// <param name="serialPortManager"></param>
            public ReceivedDelayHelper(SerialPortManager serialPortManager)
                : this(serialPortManager, 200)
            {
            }

            /// <summary>
            /// 
            /// </summary>
            /// <param name="serialPortManager"></param>
            /// <param name="delay"></param>
            public ReceivedDelayHelper(SerialPortManager serialPortManager, int delay)
            {
                if (serialPortManager == null)
                {
                    throw new ArgumentNullException("serialPortManager");
                }

                this._serialPortManager = serialPortManager;
                this.Delay = delay;
            }


            #region Delay
            /// <summary>
            /// 
            /// </summary>
            public int Delay
            {
                get
                {
                    return _delay;
                }
                set
                {
                    _delay = value;
                }
            } private int _delay;
            #endregion //Delay


            /// <summary>
            /// 
            /// </summary>
            private void ReceiveDelayFunction()
            {
                _receiveDelayStartDateTime = DateTime.Now;
                Thread.Sleep(this.Delay);
                _serialPortManager.OnReceivedEvent();
                _receiveDelayThread = null;
            }

            /// <summary>
            /// 
            /// </summary>
            public void Start()
            {
                if (_receiveDelayThread == null)
                {
                    ThreadStart start = new ThreadStart(this.ReceiveDelayFunction);
                    _receiveDelayThread = new Thread(start);
                    _receiveDelayThread.Start();
                }
            }

            /// <summary>
            /// 
            /// </summary>
            /// <returns></returns>
            public bool IsStarted()
            {
                return _receiveDelayThread != null && _receiveDelayThread.IsAlive;
            }
        }
        #endregion //ReceivedDelayHelper

        #region GetReceivedDelayHelper
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private ReceivedDelayHelper GetReceivedDelayHelper()
        {
            if (_receivedDelayHelper == null)
            {
                _receivedDelayHelper = new ReceivedDelayHelper(this);
            }
            return _receivedDelayHelper;
        } private ReceivedDelayHelper _receivedDelayHelper;
        #endregion //GetReceivedDelayHelper

        #region Open
        /// <summary>
        /// 
        /// </summary>
        public void Open()
        {
            this.SerialPort.Open();
        }
        #endregion //Open

        #region Close
        /// <summary>
        /// 
        /// </summary>
        public void Close()
        {
            this.SerialPort.Close();
        }
        #endregion //Close

        #region Event
        /// <summary>
        /// 
        /// </summary>
        public event EventHandler ReceivedEvent;
        #endregion //Event

        #region SerialPort
        /// <summary>
        /// 
        /// </summary>
        public SerialPort SerialPort
        {
            get
            {
                if (_serialPort == null)
                {
                    _serialPort = new SerialPort();
                    _serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);
                }
                return _serialPort;
            }
        } private SerialPort _serialPort;
        #endregion //SerialPort

        #region OnReceivedEvent
        /// <summary>
        /// 
        /// </summary>
        private void OnReceivedEvent()
        {
            if (this.ReceivedEvent != null)
            {
                this.ReceivedEvent(this, EventArgs.Empty);
            }
        }
        #endregion //OnReceivedEvent

        #region _serialPort_DataReceived
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            ReceivedDelayHelper h = this.GetReceivedDelayHelper();
            if (!h.IsStarted())
            {
                h.Start();
            }
        }
        #endregion //_serialPort_DataReceived

        #region ReceivedBytes
        /// <summary>
        /// 
        /// </summary>
        public byte[] ReceivedBytes
        {
            get
            {
                int count = this.SerialPort.BytesToRead;
                byte[] buffer = new byte[count];
                if (count > 0)
                {
                    this.SerialPort.Read(buffer, 0, count);
                }
                return buffer;
            }
        }
        #endregion //ReceivedBytes

        #region Write
        /// <summary>
        /// 
        /// </summary>
        /// <param name="bs"></param>
        public void Write(byte[] bs)
        {
            this.SerialPort.Write(bs, 0, bs.Length);
        }
        #endregion //Write

        #region IsOpen
        /// <summary>
        /// 
        /// </summary>
        public bool IsOpen
        {
            get { return this.SerialPort.IsOpen; }
        }
        #endregion //IsOpen

        #region SerialPortSettings
        /// <summary>
        /// 
        /// </summary>
        public SerialPortSettings SerialPortSettings
        {
            get
            {
                return _serialPortSettings;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("SerialPortSettings");
                }

                this.SerialPort.PortName = value.PortName;
                this.SerialPort.BaudRate = value.BaudRate;
                this.SerialPort.DataBits = value.DataBits;
                this.SerialPort.Parity = value.Parity;
                this.SerialPort.StopBits = value.StopBits;

                _serialPortSettings = value;
            }
        } private SerialPortSettings _serialPortSettings;
        #endregion //SerialPortSettings

        #region BaudRate
        public int BaudRate
        {
            get { return this.SerialPort.BaudRate; }
            set { this.SerialPort.BaudRate = value; }
        }
        #endregion //BaudRate

        #region StopBits
        public StopBits StopBits
        {
            get { return this.SerialPort.StopBits; }
            set { this.SerialPort.StopBits = value; }
        }
        #endregion //StopBits

        #region DataBits
        public int DataBits
        {
            get { return this.SerialPort.DataBits; }
            set { this.SerialPort.DataBits = value; }
        }
        #endregion //DataBits

        #region Parity
        public Parity Parity
        {
            get { return this.SerialPort.Parity; }
            set { this.SerialPort.Parity = value; }
        }
        #endregion //Parity
    }
}
